import * as vscode from 'vscode';
import * as cp from 'child_process';
import * as path from 'path';
import * as fs from 'fs';

export class MavenUtils {
    // 静态字段，存储输出通道实例
    private static outputChannel: vscode.OutputChannel | undefined;

    /**
     * 获取Maven可执行文件路径
     */
    public async getMavenExecutable(): Promise<string> {
        // 首先检查配置中是否定义了Maven路径
        const config = vscode.workspace.getConfiguration('maven-helper');
        let mavenPath = config.get<string>('mavenPath');
        
        if (mavenPath) {
            return mavenPath;
        }
        
        // 如果没有配置，尝试从环境变量获取
        if (process.env.M2_HOME) {
            const m2Home = process.env.M2_HOME;
            const mvnCommand = process.platform === 'win32' ? 'mvn.cmd' : 'mvn';
            mavenPath = path.join(m2Home, 'bin', mvnCommand);
            if (fs.existsSync(mavenPath)) {
                return mavenPath;
            }
        }
        
        // 如果环境变量没有，尝试从PATH中获取
        return process.platform === 'win32' ? 'mvn.cmd' : 'mvn';
    }
    
    /**
     * 执行Maven命令
     */
    public async executeMavenCommand(cwd: string, command: string): Promise<string> {
        console.log(`在 ${cwd} 执行Maven命令: ${command}`);
        const mvn = await this.getMavenExecutable();
        console.log(`使用Maven可执行文件: ${mvn}`);
        
        const outputChannel = this.getOutputChannel();
        outputChannel.appendLine(`\n---------------------------------------------`);
        outputChannel.appendLine(`执行Maven命令: ${mvn} ${command}`);
        outputChannel.appendLine(`工作目录: ${cwd}`);
        outputChannel.appendLine(`---------------------------------------------`);
        outputChannel.show(true);
        
        return new Promise<string>((resolve, reject) => {
            const fullCommand = `${mvn} ${command}`;
            console.log(`完整命令: ${fullCommand}`);
            
            // 添加超时控制
            const maxExecutionTime = 120000; // 增加到2分钟
            let stderrContent = '';
            
            try {
                // 使用spawn而不是exec，可以实时获取输出
                const childProcess = cp.spawn(
                    mvn, 
                    command.split(' '), 
                    { 
                        cwd,
                        shell: true
                    }
                );
                
                let stdoutContent = '';
                
                // 设置超时
                const timeout = setTimeout(() => {
                    if (childProcess) {
                        childProcess.kill();
                        const errorMessage = 'Maven命令执行超时，请尝试在终端中手动执行';
                        outputChannel.appendLine(`\n❌ ${errorMessage}`);
                        reject(new Error(errorMessage));
                    }
                }, maxExecutionTime);
                
                // 实时输出stdout
                childProcess.stdout.on('data', (data: Buffer) => {
                    const text = data.toString();
                    stdoutContent += text;
                    outputChannel.append(text);
                });
                
                // 实时输出stderr
                childProcess.stderr.on('data', (data: Buffer) => {
                    const text = data.toString();
                    stderrContent += text;
                    outputChannel.append(text);
                });
                
                childProcess.on('error', (error: Error) => {
                    clearTimeout(timeout);
                    const errorMessage = `执行Maven命令失败: ${error.message}`;
                    outputChannel.appendLine(`\n❌ ${errorMessage}`);
                    console.error(errorMessage);
                    reject(new Error(errorMessage));
                });
                
                childProcess.on('close', (code: number) => {
                    clearTimeout(timeout);
                    
                    if (code !== 0) {
                        const errorMessage = `Maven命令执行失败，退出码: ${code}`;
                        outputChannel.appendLine(`\n❌ ${errorMessage}`);
                        console.error(errorMessage);
                        console.error(`标准错误: ${stderrContent}`);
                        reject(new Error(`${errorMessage}: ${stderrContent || 'Unknown error'}`));
                        return;
                    }
                    
                    outputChannel.appendLine(`\n✅ Maven命令执行成功 (退出码: ${code})`);
                    console.log('Maven命令执行成功');
                    resolve(stdoutContent);
                });
            } catch (error) {
                const errorMessage = `启动Maven命令失败: ${error}`;
                outputChannel.appendLine(`\n❌ ${errorMessage}`);
                console.error(errorMessage);
                reject(new Error(errorMessage));
            }
        });
    }

    /**
     * 获取或创建输出通道
     */
    private getOutputChannel(): vscode.OutputChannel {
        // 使用单例模式获取或创建输出通道
        if (!MavenUtils.outputChannel) {
            MavenUtils.outputChannel = vscode.window.createOutputChannel("Maven Helper");
        }
        return MavenUtils.outputChannel;
    }

    /**
     * 诊断Maven设置
     */
    public async diagnoseMavenSetup(): Promise<void> {
        const outputChannel = this.getOutputChannel();
        outputChannel.clear();
        outputChannel.show(true);
        
        outputChannel.appendLine('====== Maven Helper 诊断信息 ======');
        outputChannel.appendLine(`系统信息: ${process.platform} (${process.arch})`);
        outputChannel.appendLine(`Node.js 版本: ${process.version}`);
        outputChannel.appendLine('');
        
        // 检查Maven路径
        outputChannel.appendLine('检查Maven可执行文件...');
        try {
            const mavenPath = await this.getMavenExecutable();
            outputChannel.appendLine(`✅ Maven路径: ${mavenPath}`);
            
            // 检查Maven版本
            try {
                const mvnVersionOutput = await new Promise<string>((resolve, reject) => {
                    cp.exec(`${mavenPath} --version`, (error: Error | null, stdout: string) => {
                        if (error) {
                            reject(error);
                        } else {
                            resolve(stdout);
                        }
                    });
                });
                
                outputChannel.appendLine(`✅ Maven版本信息:\n${mvnVersionOutput.split('\n').slice(0, 3).join('\n')}`);
            } catch (error) {
                outputChannel.appendLine(`❌ 无法获取Maven版本: ${error}`);
            }
        } catch (error) {
            outputChannel.appendLine(`❌ Maven路径获取失败: ${error}`);
        }
        
        // 检查环境变量
        outputChannel.appendLine('\n检查环境变量...');
        outputChannel.appendLine(`JAVA_HOME: ${process.env.JAVA_HOME || '未设置'}`);
        outputChannel.appendLine(`M2_HOME: ${process.env.M2_HOME || '未设置'}`);
        outputChannel.appendLine(`PATH: ${process.env.PATH?.substring(0, 100)}...`);
        
        // 检查用户设置
        outputChannel.appendLine('\n检查VS Code设置...');
        const config = vscode.workspace.getConfiguration('maven-helper');
        const mavenPathSetting = config.get<string>('mavenPath');
        outputChannel.appendLine(`maven-helper.mavenPath: ${mavenPathSetting || '未设置 (使用自动检测)'}`);
        
        // 提示解决方法
        outputChannel.appendLine('\n====== 故障排除 ======');
        outputChannel.appendLine('如果Maven命令执行失败，请尝试以下解决方案:');
        outputChannel.appendLine('1. 确保Maven已正确安装且可在命令行中执行 "mvn --version"');
        outputChannel.appendLine('2. 设置环境变量 JAVA_HOME 指向有效的JDK安装路径');
        outputChannel.appendLine('3. 在设置中配置 maven-helper.mavenPath 指向Maven可执行文件的完整路径');
        outputChannel.appendLine('4. 确保项目的pom.xml文件有效且可在命令行中执行 "mvn dependency:tree"');
        outputChannel.appendLine('5. 尝试在终端中手动运行命令，查看具体错误信息');
        
        return;
    }

    // 简单实现其他必要方法
    public async findRootPom(startPath: string): Promise<string | undefined> {
        return path.join(startPath, 'pom.xml');
    }
    
    public async findAllPomFiles(): Promise<vscode.Uri[]> {
        return vscode.workspace.findFiles('**/pom.xml', '**/node_modules/**');
    }

    /**
     * 执行Maven命令（增强版）
     * 即使命令返回非零退出码，也尝试使用已收集的输出
     */
    public async executeMavenCommandWithErrorHandling(projectPath: string, command: string): Promise<string> {
        console.log(`在 ${projectPath} 执行Maven命令(增强版): ${command}`);
        const mvn = await this.getMavenExecutable();
        console.log(`使用Maven可执行文件: ${mvn}`);
        
        const outputChannel = this.getOutputChannel();
        outputChannel.appendLine(`\n---------------------------------------------`);
        outputChannel.appendLine(`执行Maven命令(增强版): ${mvn} ${command}`);
        outputChannel.appendLine(`工作目录: ${projectPath}`);
        outputChannel.appendLine(`---------------------------------------------`);
        outputChannel.show(true);
        
        return new Promise<string>((resolve, reject) => {
            const args = command.split(/\s+/);
            
            // 设置进程环境变量以避免中文乱码
            const env = Object.assign({}, process.env);
            if (process.platform === 'win32') {
                env['JAVA_TOOL_OPTIONS'] = `-Dfile.encoding=UTF-8`;
            }
            
            let stdoutContent = '';
            let stderrContent = '';
            
            // 添加超时控制
            const maxExecutionTime = 180000; // 3分钟
            
            try {
                // 使用spawn允许实时获取输出
                const childProcess = cp.spawn(
                    mvn, 
                    args, 
                    { 
                        cwd: projectPath,
                        env: env,
                        shell: true
                    }
                );
                
                // 设置超时
                const timeout = setTimeout(() => {
                    if (childProcess) {
                        childProcess.kill();
                        const errorMessage = 'Maven命令执行超时，请尝试在终端中手动执行';
                        outputChannel.appendLine(`\n❌ ${errorMessage}`);
                        reject(new Error(errorMessage));
                    }
                }, maxExecutionTime);
                
                // 实时输出stdout
                childProcess.stdout.on('data', (data: Buffer) => {
                    const text = data.toString();
                    stdoutContent += text;
                    outputChannel.append(text);
                });
                
                // 实时输出stderr
                childProcess.stderr.on('data', (data: Buffer) => {
                    const text = data.toString();
                    stderrContent += text;
                    outputChannel.append(text);
                });
                
                childProcess.on('error', (error: Error) => {
                    clearTimeout(timeout);
                    const errorMessage = `执行Maven命令失败: ${error.message}`;
                    outputChannel.appendLine(`\n❌ ${errorMessage}`);
                    console.error(errorMessage);
                    reject(new Error(errorMessage));
                });
                
                childProcess.on('close', (code: number) => {
                    clearTimeout(timeout);
                    
                    if (code !== 0) {
                        const errorMessage = `Maven命令执行失败，退出码: ${code}`;
                        outputChannel.appendLine(`\n⚠️ ${errorMessage}`);
                        console.warn(errorMessage);
                        
                        // 关键区别：尽管命令失败，如果有输出，我们仍然尝试继续处理
                        if (stdoutContent.length > 0) {
                            outputChannel.appendLine(`\n即使命令返回错误码，仍继续处理收集到的输出 (${stdoutContent.length} 字节)`);
                            resolve(stdoutContent);
                        } else {
                            outputChannel.appendLine(`\n❌ 无有效输出可供处理`);
                            reject(new Error(`${errorMessage}: ${stderrContent || 'Unknown error'}`));
                        }
                        return;
                    }
                    
                    outputChannel.appendLine(`\n✅ Maven命令执行成功 (退出码: ${code})`);
                    console.log('Maven命令执行成功');
                    resolve(stdoutContent);
                });
            } catch (error) {
                const errorMessage = `启动Maven命令失败: ${error}`;
                outputChannel.appendLine(`\n❌ ${errorMessage}`);
                console.error(errorMessage);
                reject(new Error(errorMessage));
            }
        });
    }
}
